home *** CD-ROM | disk | FTP | other *** search
/ HPAVC / HPAVC CD-ROM.iso / ABUSESRC.ZIP / AbuseSrc / imlib / image.c < prev    next >
C/C++ Source or Header  |  1996-05-17  |  32KB  |  1,343 lines

  1. #include "image.hpp"
  2. #include "macs.hpp"
  3. #include "system.h"
  4. #include "system.h"
  5.  
  6. #include <math.h>
  7. #ifdef __DOS
  8.   #include <dir.h>
  9. #else
  10.   #include <unistd.h>
  11. #endif
  12. #include <stdlib.h>
  13.  
  14. extern unsigned char current_background;
  15. char *imerr_messages[]={"No error",
  16.                    "Error occured while reading",
  17.             "Incorrect file type",
  18.             "File is corrupted",
  19.              "File not found",
  20.             "Memory allocation trouble",
  21.             "Operation/file type not supported",
  22.             "Error occured while writing, (disk full?)"};
  23.             
  24.                          
  25. short imerror=0;
  26. short swpfile_num=0;
  27.  
  28. short current_error()
  29. { return imerror; }
  30.  
  31. void clear_errors()
  32. {
  33.   if (imerror)
  34.   { printf("Program stopped, error : ");
  35.     if (imerror<=imMAX_ERROR)
  36.       printf("%s\n",imerr_messages[imerror]);
  37.     else
  38.       printf("Unsonsponsered error code, you got trouble\n"); 
  39. #ifdef __DOS_ONLY
  40.     sound(300);
  41.     delay(100);
  42.     nosound();
  43. #else
  44.     printf("%c%c\n",7,8);
  45. #endif
  46.     exit(1);
  47.   }
  48. }
  49.  
  50. void set_error(short x)
  51. { imerror=x; }
  52.  
  53. short last_error()
  54. {
  55.   short ec;
  56.   ec=imerror;
  57.   imerror=0;
  58.   return ec;
  59. }
  60.  
  61. linked_list image_list;
  62.  
  63.  
  64. image_descriptor::image_descriptor(short length, short height,
  65.                    int keep_dirties, int static_memory)
  66.  
  67. { clipx1=0; clipy1=0; 
  68.   l=length; h=height; 
  69.   clipx2=l-1; clipy2=h-1; 
  70.   keep_dirt=keep_dirties; 
  71.   static_mem=static_memory;  
  72. }
  73.  
  74. void image::change_size(short new_width, short new_height, unsigned char *page)
  75. {
  76.   delete_page();
  77.   w=new_width;
  78.   h=new_height;
  79.   make_page(new_width,new_height,page);
  80. }
  81.  
  82. image::~image()
  83. {
  84.   image_list.unlink((linked_node *)this);
  85.   delete_page();
  86.   if (special)
  87.     delete special;
  88.  
  89. }
  90.  
  91.  
  92. void make_block(size_t size)
  93. {
  94.   void *dat=jmalloc(size,"make_block : tmp");
  95.   CONDITION(dat,"Memory error : could not make block\n");
  96.   if (dat) jfree((char *)dat);
  97. }
  98.  
  99. unsigned char image::pixel(short x, short y)
  100. {
  101.   CONDITION(x>=0 && x<width() && y>=0 && y<height(),
  102.      "image::pixel Bad pixel xy");
  103.   return (*(scan_line(y)+x));
  104. }
  105.  
  106. void image::putpixel(short x, short y, char color)
  107. {
  108.   CONDITION(x>=0 && x<width() && y>=0 && y<height(),
  109.      "image::putpixel Bad pixel xy");
  110.   if (special)
  111.   { if (x>=special->x1_clip() && x<=special->x2_clip() &&
  112.     y>=special->y1_clip() && y<=special->y2_clip())
  113.       (*(scan_line(y)+x))=color;
  114.   } else (*(scan_line(y)+x))=color;
  115. }
  116.  
  117.  
  118. image::image(short width, short height, unsigned char *page_buffer, short create_descriptor)
  119. {
  120.   w=width;
  121.   h=height;  
  122.   if (create_descriptor || page_buffer)
  123.   { 
  124.     if (create_descriptor==2)
  125.       special=new image_descriptor(width,height,1,(page_buffer!=NULL));
  126.     else special=new image_descriptor(width,height,0,(page_buffer!=NULL));
  127.   } else special=NULL;
  128.   make_page(width,height,page_buffer);
  129.   image_list.add_end((linked_node *) this);
  130. }
  131.  
  132. image::image(spec_entry *e, bFILE *fp)
  133. {
  134.   short i; 
  135.   fp->seek(e->offset,0);
  136.   w=fp->read_short();
  137.   h=fp->read_short();
  138.   special=NULL;
  139.   make_page(w,h,NULL);
  140.   for (i=0;i<h;i++)
  141.     fp->read(scan_line(i),w);
  142.   image_list.add_end((linked_node *) this); 
  143. }
  144.  
  145. image::image(bFILE *fp)
  146. {
  147.   short i; 
  148.   w=fp->read_short();
  149.   h=fp->read_short();
  150.   special=NULL;
  151.   make_page(w,h,NULL);
  152.   for (i=0;i<h;i++)
  153.     fp->read(scan_line(i),w);
  154.   image_list.add_end((linked_node *) this); 
  155. }
  156.  
  157. void image_uninit()
  158. {
  159. /*  image *im;
  160.   while (image_list.first())
  161.   {
  162.     im=(image *)image_list.first();
  163.     image_list.unlink((linked_node *)im);
  164.     delete im;
  165.   } */
  166. }
  167.  
  168.  
  169. void image_cleanup(int ret, void *arg)
  170. { image_uninit(); }
  171.  
  172. void image_init()
  173. {
  174.   unsigned char bt[2];
  175.   unsigned short wrd,*up;
  176.   bt[0]=1;
  177.   bt[1]=0;
  178.   up=(unsigned short *)bt;
  179.   wrd=int_to_intel(*up);
  180.   if (wrd!=0x01)
  181.   { printf("Compiled under wrong ENDING-nes, edit system.h and try again\n");
  182.     printf("1 (intel) = %d\n",(int)wrd);
  183.     exit(1);
  184.   }
  185.   imerror=0;
  186. }
  187.  
  188.  
  189. long image::total_pixels(unsigned char background)
  190. {
  191.   short i,j;
  192.   long co;
  193.   unsigned char *c;
  194.   for (co=0,i=height()-1;i>=0;i--)
  195.   { c=scan_line(i);
  196.     for (j=width()-1;j>=0;j--,c++)
  197.       if (*c!=background) co++;
  198.   }
  199.   return co;
  200. }
  201.  
  202. void image::clear(short color)
  203. {
  204.   short i;
  205.   if (color==-1) color=current_background;
  206.   if (special)
  207.   { if (special->x1_clip()<=special->x2_clip())
  208.       for (i=special->y2_clip();i>=special->y1_clip();i--)
  209.     memset(scan_line(i)+special->x1_clip(),color,
  210.            special->x2_clip()-special->x1_clip()+1);
  211.   }
  212.   else
  213.     for (i=height()-1;i>=0;i--)
  214.       memset(scan_line(i),color,width());
  215.   add_dirty(0,0,width()-1,height()-1);
  216. }
  217.  
  218.  
  219. image *image::copy()
  220. {
  221.   image *im;
  222.   unsigned char *c,*dat;
  223.   int i;
  224.   dat=(unsigned char *)jmalloc(width(),"image copy");
  225.   im=new image(width(),height());
  226.   for (i=height()-1;i>=0;i--)
  227.   { c=scan_line(i);
  228.     memcpy(dat,c,width());
  229.     c=im->scan_line(i);
  230.     memcpy(c,dat,width());
  231.   }
  232.   jfree((char *)dat);
  233.   return im;
  234. }
  235.  
  236.  
  237.  
  238. void image::line(short x1, short y1,short x2, short y2, unsigned char color)
  239. {
  240.   short i,xc,yc,er,n,m,xi,yi,xcxi,ycyi,xcyi;
  241.   unsigned dcy,dcx;
  242.   // check to make sure that both endpoint are on the screen
  243.  
  244.   short cx1,cy1,cx2,cy2;
  245.  
  246.   // check to see if the line is completly clipped off
  247.   get_clip(cx1,cy1,cx2,cy2);  
  248.   if ((x1<cx1 && x2<cx1) || (x1>cx2 && x2>cx2) || 
  249.       (y1<cy1 && y2<cy1) || (y1>cy2 && y2>cy2))
  250.     return ;
  251.  
  252.   if (x1>x2)        // make sure that x1 is to the left
  253.   {    
  254.     i=x1; x1=x2; x2=i;  // if not swap points
  255.     i=y1; y1=y2; y2=i;
  256.   }  
  257.  
  258.   // clip the left side
  259.   if (x1<cx1)
  260.   {  
  261.     int my=(y2-y1);       
  262.     int mx=(x2-x1),b;
  263.     if (!mx) return ;
  264.     if (my)
  265.     {
  266.       b=y1-(y2-y1)*x1/mx;      
  267.       y1=my*cx1/mx+b;
  268.       x1=cx1;      
  269.     }
  270.     else x1=cx1;
  271.   }
  272.  
  273.   // clip the right side
  274.   if (x2>cx2)
  275.   {  
  276.     int my=(y2-y1);       
  277.     int mx=(x2-x1),b;
  278.     if (!mx) return ;
  279.     if (my)
  280.     {
  281.       b=y1-(y2-y1)*x1/mx;      
  282.       y2=my*cx2/mx+b;
  283.       x2=cx2;      
  284.     }
  285.     else x2=cx2;
  286.   }
  287.  
  288.   if (y1>y2)        // make sure that y1 is on top
  289.   {    
  290.     i=x1; x1=x2; x2=i;  // if not swap points
  291.     i=y1; y1=y2; y2=i;
  292.   }  
  293.  
  294.   // clip the bottom
  295.   if (y2>cy2)
  296.   {  
  297.     int mx=(x2-x1);       
  298.     int my=(y2-y1),b;
  299.     if (!my)
  300.       return ;
  301.     if (mx)
  302.     {
  303.       b=y1-(y2-y1)*x1/mx;      
  304.       x2=(cy2-b)*mx/my;
  305.       y2=cy2;
  306.     }
  307.     else y2=cy2;
  308.   }
  309.  
  310.   // clip the top
  311.   if (y1<cy1)
  312.   {  
  313.     int mx=(x2-x1);       
  314.     int my=(y2-y1),b;
  315.     if (!my) return ;
  316.     if (mx)
  317.     {
  318.       b=y1-(y2-y1)*x1/mx;      
  319.       x1=(cy1-b)*mx/my;
  320.       y1=cy1;
  321.     }
  322.     else y1=cy1;
  323.   }
  324.  
  325.  
  326.   // see if it got cliped into the box, out out
  327.   if (x1<cx1 || x2<cx1 || x1>cx2 || x2>cx2 || y1<cy1 || y2 <cy1 || y1>cy2 || y2>cy2)
  328.     return ;
  329.   
  330.     
  331.  
  332.   if (x1>x2)
  333.   { xc=x2; xi=x1; }
  334.   else { xi=x2; xc=x1; }
  335.  
  336.  
  337.   // assume y1<=y2 from above swap operation
  338.   yi=y2; yc=y1;
  339.  
  340.   add_dirty(xc,yc,xi,yi);
  341.   dcx=x1; dcy=y1;
  342.   xc=(x2-x1); yc=(y2-y1);
  343.   if (xc<0) xi=-1; else xi=1;
  344.   if (yc<0) yi=-1; else yi=1;
  345.   n=abs(xc); m=abs(yc);
  346.   ycyi=abs(2*yc*xi);
  347.   er=0;
  348.  
  349.   if (n>m)
  350.   {
  351.     xcxi=abs(2*xc*xi);
  352.     for (i=0;i<=n;i++)
  353.     {
  354.       *(scan_line(dcy)+dcx)=color;
  355.       if (er>0)
  356.       { dcy+=yi;
  357.     er-=xcxi;
  358.       }
  359.       er+=ycyi;
  360.       dcx+=xi;
  361.     }
  362.   }
  363.   else
  364.   {
  365.     xcyi=abs(2*xc*yi);
  366.     for (i=0;i<=m;i++)
  367.     {
  368.       *(scan_line(dcy)+dcx)=color;
  369.       if (er>0)
  370.       { dcx+=xi;
  371.     er-=ycyi;
  372.       }
  373.       er+=xcyi;
  374.       dcy+=yi;
  375.     }
  376.   }
  377. }
  378.  
  379.  
  380. void image::put_image(image *screen, short x, short y, char transparent)
  381. {
  382.   short i,j,xl,yl;
  383.   unsigned char *pg1,*pg2,*source,*dest;
  384.   if (screen->special)  // the screen is clipped then we onl want to put
  385.             // part of the image
  386.     put_part(screen,x,y,0,0,width()-1,height()-1,transparent);
  387.   else
  388.   {
  389.     if (x<screen->width() && y<screen->height())
  390.     {
  391.       xl=width();
  392.       if (x+xl>screen->width())     // clip to the border of the screen
  393.     xl=screen->width()-x;
  394.       yl=height();
  395.       if (y+yl>screen->height())
  396.     yl=screen->height()-y;
  397.  
  398.       int startx=0,starty=0;
  399.       if (x<0) { startx=-x; x=0; }
  400.       if (y<0) { starty=-y; y=0; }
  401.  
  402.       if (xl<0 || yl<0) return ;
  403.  
  404.       screen->add_dirty(x,y,x+xl-1,y+yl-1);
  405.       for (j=starty;j<yl;j++,y++)
  406.       {
  407.     pg1=screen->scan_line(y);
  408.     pg2=scan_line(j);
  409.     if (transparent)
  410.     {
  411.       for (i=startx,source=pg2+startx,dest=pg1+x;i<xl;i++,source++,dest++)
  412.             if (*source!=current_background) *dest=*source;
  413.     } else memcpy(&pg1[x],pg2,xl);   // strait copy
  414.       }
  415.     }
  416.   }
  417. }
  418.  
  419. void image::fill_image(image *screen, short x1, short y1, short x2, short y2, short allign)
  420. {
  421.   short i,j,w,xx,start,xl,starty;
  422.   unsigned char *pg1,*pg2;
  423.   CHECK(x1<=x2 && y1<=y2);  // we should have gotten this
  424.  
  425.   if (screen->special)
  426.   { x1=screen->special->bound_x1(x1);
  427.     y1=screen->special->bound_y1(y1);
  428.     x2=screen->special->bound_x2(x2);
  429.     y2=screen->special->bound_y2(y2);
  430.   }
  431.   else
  432.   { if (x1<0) x1=0;
  433.     if (y2<0) y1=0;
  434.     if (x2>=screen->width())  x2=screen->width()-1;
  435.     if (y2>=screen->height()) y2=screen->height()-1;
  436.   }
  437.   if (x2<0 || y2<0 || x1>=screen->width() || y1>=screen->height())
  438.     return ;
  439.   screen->add_dirty(x1,y1,x2,y2);
  440.   w=width();
  441.   if (allign)
  442.   {
  443.     start=x1%w;
  444.     starty=y1%height();
  445.   }
  446.   else
  447.   { start=0;
  448.     starty=0;
  449.   }
  450.   for (j=y1;j<=y2;j++)
  451.   {
  452.     pg1=screen->scan_line(j);
  453.     pg2=scan_line(starty++);
  454.     if (starty>=height()) starty=0;
  455.     i=x1;
  456.     xx=start;
  457.     while (i<=x2)
  458.     {
  459.       xl=min(w-xx,x2-i+1);
  460.  
  461.       memcpy(&pg1[i],&pg2[xx],xl);
  462.       xx=0;
  463.       i+=xl;
  464.     }
  465.   }
  466. }
  467.  
  468.  
  469. void image::put_part(image *screen, short x, short y,
  470.         short x1, short y1, short x2, short y2, char transparent)
  471. {
  472.   short xl,yl,j,i;
  473.   short cx1,cy1,cx2,cy2;
  474.   unsigned char *pg1,*pg2,*source,*dest;
  475.   CHECK(x1<=x2 && y1<=y2);
  476.  
  477.   screen->get_clip(cx1,cy1,cx2,cy2);
  478.  
  479.  
  480.   // see if the are to be put is outside of actual image, if so adjust 
  481.   // to fit in the image
  482.   if (x1<0) { x+=-x1; x1=0; }  
  483.   if (y1<0) { y+=-y1; y1=0; }  
  484.   if (x2>=width()) x2=width()-1;
  485.   if (y2>=height()) y2=height()-1;
  486.   if (x1>x2 || y1>y2) return ;      // return if it was adjusted so that nothing will be put
  487.     
  488.  
  489.   // see if the image gets clipped of the screen
  490.   if (x>cx2 || y>cy2 || x+(x2-x1)<cx1 || y+(y2-y1)<cy1) return ;
  491.  
  492.   
  493.   if (x<cx1)
  494.   { x1+=(cx1-x); x=cx1; }
  495.   if (y<cy1)
  496.   { y1+=(cy1-y); y=cy1; }
  497.  
  498.   if (x+x2-x1+1>cx2)
  499.   { x2=cx2-x+x1; }
  500.  
  501.   if (y+y2-y1+1>cy2)
  502.   { y2=cy2-y+y1; }
  503.   if (x1>x2 || y1>y2) return ;    
  504.  
  505.   
  506.  
  507.  
  508.   xl=x2-x1+1;
  509.   yl=y2-y1+1;
  510.  
  511.   screen->add_dirty(x,y,x+xl-1,y+yl-1);
  512.  
  513.   pg1=screen->scan_line(y);
  514.   pg2=scan_line(y1);
  515.  
  516.   if (transparent)
  517.   {
  518.     for (j=0;j<yl;j++)        
  519.     {
  520.       for (i=0,source=&pg2[x1],dest=&pg1[x];i<xl;i++,source++,dest++)    
  521.         if (*source!=current_background) *dest=*source;
  522.       pg1=screen->next_line(y+j,pg1);  
  523.       pg2=next_line(y1+j,pg2);
  524.     }      
  525.   }
  526.   else
  527.   for (j=0;j<yl;j++)
  528.   {    
  529.     memcpy(&pg1[x],&pg2[x1],xl);   // strait copy
  530.     pg1=screen->next_line(y+j,pg1);  
  531.     pg2=next_line(y1+j,pg2);
  532.   }    
  533. }
  534.  
  535. void image::put_part_xrev(image *screen, short x, short y,
  536.         short x1, short y1, short x2, short y2, char transparent)
  537. {
  538.   short xl,yl,j,i;
  539.   short cx1,cy1,cx2,cy2;
  540.   unsigned char *pg1,*pg2,*source,*dest;
  541.   CHECK(x1<=x2 && y1<=y2);
  542.  
  543.   i=x1; x1=width()-x2-1;  // reverse the x locations
  544.   x2=width()-i-1;
  545.  
  546.   if (x1<0)
  547.   { x-=x1; x1=0; }
  548.   if (y1<0)
  549.   { y-=y1; y1=0; }
  550.  
  551.   if (screen->special)
  552.   {
  553.     screen->special->get_clip(cx1,cy1,cx2,cy2);
  554.     if (x>cx2 || y>cy2 || x+(x2-x1)<0 || y+(y2-y1)<0) return ;
  555.     if (x<cx1)
  556.     { x1+=(cx1-x); x=cx1; }
  557.     if (y<cy1)
  558.     { y1+=(cy1-y); y=cy1; }
  559.     if (x+x2-x1+1>cx2)
  560.     { x2=cx2-x+x1; }
  561.     if (y+y2-y1+1>cy2)
  562.     { y2=cy2-y+y1; }
  563.   }
  564.   else  if (x>screen->width() || y>screen->height() || x+x2<0 || y+y2<0)
  565.     return ;
  566.  
  567.   if (x<screen->width() && y<screen->height() && x1<width() && y1<height() &&
  568.       x1<=x2 && y1<=y2)
  569.   {
  570.     if (x2>=width())
  571.       x2=width()-1;
  572.     if (y2>=height())
  573.       y2=height()-1;
  574.     xl=x2-x1+1;
  575.     if (x+xl>screen->width())
  576.       xl=screen->width()-x;
  577.     yl=y2-y1+1;
  578.     if (y+yl>screen->height())
  579.       yl=screen->height()-y;
  580.     screen->add_dirty(x,y,x+xl-1,y+yl-1);
  581.     for (j=0;j<yl;j++)
  582.     {
  583.       pg1=screen->scan_line(y+j);
  584.       pg2=scan_line(y1+j);
  585.       if (transparent)
  586.       {
  587.     for (i=0,source=&pg2[x1],dest=&pg1[x+xl-1];i<xl;i++,source++,dest--)
  588.           if (*source!=current_background) *dest=*source;
  589.       }
  590.       else 
  591.     for (i=0,source=&pg2[x1],dest=&pg1[x+xl-1];i<xl;i++,source++,dest++)
  592.           *dest=*source;
  593.     }
  594.   }
  595. }
  596.  
  597.  
  598. void image::put_part_masked(image *screen, image *mask, short x, short y,
  599.         short maskx, short masky,
  600.         short x1, short y1, short x2, short y2)
  601. {
  602.   short xl,yl,j,i,ml,mh;
  603.   short cx1,cy1,cx2,cy2;
  604.   unsigned char *pg1,*pg2,*pg3;
  605.   CHECK(x1<=x2 && y1<=y2);
  606.  
  607.   if (screen->special)
  608.   {
  609.     screen->special->get_clip(cx1,cy1,cx2,cy2);
  610.     if (x>cx2 || y>cy2 || x+(x2-x1)<0 || y+(y2-y1)<0) return ;
  611.     if (x<cx1)
  612.     { x1+=(cx1-x); x=cx1; }
  613.     if (y<cy1)
  614.     { y1+=(cy1-y); y=cy1; }
  615.     if (x+x2-x1>cx2)
  616.     { x2=cx2+x1-x; }
  617.     if (y+y2-y1>cy2)
  618.     { y2=cy2+y1-y; }
  619.   }
  620.   else  if (x>screen->width() || y>screen->height() || x+x1<0 || y+y1<0)
  621.     return ;
  622.  
  623.   ml=mask->width();
  624.   mh=mask->height();
  625.   if (x<screen->width() && y<screen->height() && x1<width() && y1<height() &&
  626.       maskx<ml && masky<mh && x1<=x2 && y1<=y2)
  627.   {
  628.  
  629.     if (x2>=width())
  630.       x2=width()-1;
  631.     if (y2>=height())
  632.       y2=height()-1;
  633.     xl=x2-x1+1;
  634.     if (x+xl>screen->width())
  635.       xl=screen->width()-x-1;
  636.     yl=y2-y1+1;
  637.     if (y+yl>screen->height())
  638.       yl=screen->height()-y-1;
  639.     screen->add_dirty(x,y,x+xl-1,y+yl-1);
  640.     for (j=0;j<yl;j++)
  641.     {
  642.       pg1=screen->scan_line(y+j);
  643.       pg2=scan_line(y1+j);
  644.       pg3=mask->scan_line(masky++);
  645.       if (masky>=mh)           // wrap the mask around if out of bounds
  646.     masky=0;
  647.       for (i=0;i<xl;i++)
  648.       {
  649.     if (pg3[maskx+i])          // check to make sure not 0 before putting
  650.       pg1[x+i]=pg2[x1+i];
  651.     if (maskx>=ml)            // wrap x around if it goes to far
  652.       maskx=0;
  653.       }
  654.     }
  655.   }
  656. }
  657.  
  658.  
  659.  
  660. unsigned char image::brightest_color(palette *pal)
  661. { unsigned char *p,r,g,b,bri;
  662.   short i,j;
  663.   long brv;
  664.   brv=0; bri=0;
  665.   for (j=0;j<h;j++)
  666.   {
  667.     p=scan_line(j);
  668.     for (i=0;i<w;i++)
  669.     { pal->get(p[i],r,g,b);
  670.       if ((long)r*(long)g*(long)b>brv)
  671.       { brv=(long)r*(long)g*(long)b;
  672.     bri=p[i];
  673.       }
  674.     }
  675.   }
  676.   return bri;
  677. }
  678.  
  679. unsigned char image::darkest_color(palette *pal, short noblack)
  680. { unsigned char *p,r,g,b,bri;
  681.   short i,j;
  682.   long brv,x;
  683.   brv=(long)258*(long)258*(long)258; bri=0;
  684.   for (j=0;j<h;j++)
  685.   {
  686.     p=scan_line(j);
  687.     for (i=0;i<w;i++)
  688.     { pal->get(p[i],r,g,b);
  689.       x=(long)r*(long)g*(long)b;
  690.       if (x<brv && (x || !noblack))
  691.       { brv=x;
  692.     bri=p[i];
  693.       }
  694.     }
  695.   }
  696.   return bri;
  697. }
  698.  
  699. void image::rectangle(short x1, short y1,short x2, short y2, unsigned char color)
  700. {
  701.   line(x1,y1,x2,y1,color);
  702.   line(x2,y1,x2,y2,color);
  703.   line(x1,y2,x2,y2,color);
  704.   line(x1,y1,x1,y2,color);
  705. }
  706.  
  707. void image::set_clip(short x1, short y1, short x2, short y2)
  708. {
  709.   // If the image does not already have an Image descriptor, allocate one.
  710.  
  711.   if (!special)
  712.   { 
  713.     // create a new image descriptor withj no dirty rectangle keeping
  714.     special=new image_descriptor(width(),height(),0);
  715.   }
  716.   special->set_clip(x1,y1,x2,y2);  // set the image descriptor what the clip
  717.                // should be it will adjust to fit wiothin the image.
  718. }
  719.  
  720. void image::get_clip (short &x1, short &y1, short &x2, short &y2)
  721. {
  722.   if (special)
  723.     special->get_clip(x1,y1,x2,y2);
  724.   else
  725.   { x1=0; y1=0; x2=width()-1; y2=height()-1; }
  726. }
  727.  
  728. void image::in_clip  (short x1, short y1, short x2, short y2)
  729. {
  730.   if (special)
  731.   {
  732.     if (x1<special->x1_clip())
  733.       x1=special->x1_clip();
  734.     if (y1<special->y1_clip())
  735.       y1=special->y1_clip();
  736.     if (x2>special->x2_clip())
  737.       x2=special->x2_clip();
  738.     if (y2>special->y2_clip())
  739.       y2=special->y2_clip();
  740.   }
  741.   set_clip(x1,y1,x2,y2);
  742. }
  743. // this function reduces the number of dirty rectanges
  744. // to 1 by find the minmum area that can contain all the rectangles and
  745. // making this the new dirty area
  746. void image_descriptor::reduce_dirties()
  747. {
  748.   dirty_rect *p,*q;
  749.   short x1,y1,x2,y2,nn;
  750.   x1=6000; y1=6000;
  751.   x2=0; y2=0;
  752.   p=(dirty_rect *)dirties.first();
  753.   nn=dirties.number_nodes();
  754.   while (nn>0)
  755.   {
  756.     if (p->dx1<x1) x1=p->dx1;
  757.     if (p->dy1<y1) y1=p->dy1;
  758.     if (p->dx2>x2) x2=p->dx2;
  759.     if (p->dy2>y2) y2=p->dy2;
  760.     q=p;
  761.     p=(dirty_rect *)p->next();
  762.     dirties.unlink((linked_node *)q);
  763.     delete q;
  764.     nn--;
  765.   }
  766.   dirties.add_front((linked_node *) new dirty_rect(x1,y1,x2,y2));
  767. }
  768.  
  769. void image_descriptor::delete_dirty(int x1, int y1, int x2, int y2)
  770. {
  771.   short i,ax1,ay1,ax2,ay2;
  772.   dirty_rect *p,*next;
  773.   if (keep_dirt)
  774.   {
  775.     if (x1<0) x1=0;
  776.     if (y1<0) y1=0;
  777.     if (x2>=(int)l) x2=l-1;
  778.     if (y2>=(int)h) y2=h-1;
  779.     if (x1>x2) return;
  780.     if (y1>y2) return ;
  781.  
  782.     i=dirties.number_nodes();
  783.     if (!i)
  784.       return ;
  785.     else
  786.     {
  787.       for (p=(dirty_rect *)dirties.first();i;i--,p=(dirty_rect *)next)
  788.       {
  789.         next=(dirty_rect *)p->next();
  790.         // are the two touching?
  791.     if (!(x2<p->dx1 || y2<p->dy1 || x1>p->dx2 || y1>p->dy2))
  792.         {
  793.           // does it take a x slice off? (across)
  794.           if (x2>=p->dx2 && x1<=p->dx1)
  795.           {
  796.             if (y2>=p->dy2 && y1<=p->dy1)
  797.             {
  798.               dirties.unlink((linked_node *)p);
  799.               delete p;
  800.             } 
  801.             else if (y2>=p->dy2)
  802.               p->dy2=y1-1;
  803.             else if (y1<=p->dy1)
  804.               p->dy1=y2+1;
  805.             else
  806.             {
  807.               dirties.add_front((linked_node *) new dirty_rect(p->dx1,p->dy1,p->dx2,y1-1));
  808.               p->dy1=y2+1;
  809.             }
  810.           } 
  811.           // does it take a y slice off (down)
  812.           else if (y2>=p->dy2 && y1<=p->dy1)
  813.           {
  814.             if (x2>=p->dx2)
  815.               p->dx2=x1-1;
  816.             else if (x1<=p->dx1)
  817.               p->dx1=x2+1;
  818.             else 
  819.             {
  820.               dirties.add_front((linked_node *) new dirty_rect(p->dx1,p->dy1,x1-1,p->dy2));
  821.               p->dx1=x2+1;
  822.             }
  823.           }
  824.           // otherwise it just takes a little chunk off
  825.           else 
  826.           {
  827.             if (x2>=p->dx2)      { ax1=p->dx1; ax2=x1-1; }
  828.             else if (x1<=p->dx1) { ax1=x2+1; ax2=p->dx2; }
  829.             else                { ax1=p->dx1; ax2=x1-1; } 
  830.             if (y2>=p->dy2)      { ay1=y1; ay2=p->dy2; }
  831.             else if (y1<=p->dy1) { ay1=p->dy1; ay2=y2; }
  832.             else                { ay1=y1; ay2=y2; }
  833.             dirties.add_front((linked_node *) new dirty_rect(ax1,ay1,ax2,ay2));
  834.           
  835.             if (x2>=p->dx2 || x1<=p->dx1)  { ax1=p->dx1; ax2=p->dx2; }
  836.             else                         { ax1=x2+1; ax2=p->dx2; } 
  837.  
  838.             if (y2>=p->dy2)
  839.             { if (ax1==p->dx1) { ay1=p->dy1; ay2=y1-1; }
  840.                           else { ay1=y1; ay2=p->dy2;   } }
  841.             else if (y1<=p->dy1) { if (ax1==p->dx1) { ay1=y2+1; ay2=p->dy2; }
  842.                                              else  { ay1=p->dy1; ay2=y2; } }
  843.             else           { if (ax1==p->dx1) { ay1=p->dy1; ay2=y1-1; }
  844.                              else { ay1=y1; ay2=y2; } }
  845.             dirties.add_front((linked_node *) new dirty_rect(ax1,ay1,ax2,ay2));
  846.  
  847.             if (x1>p->dx1 && x2<p->dx2)
  848.             {
  849.               if (y1>p->dy1 && y2<p->dy2)
  850.               {
  851.                 dirties.add_front((linked_node *) new dirty_rect(p->dx1,p->dy1,p->dx2,y1-1));
  852.                 dirties.add_front((linked_node *) new dirty_rect(p->dx1,y2+1,p->dx2,p->dy2));
  853.               } else if (y1<=p->dy1)
  854.                 dirties.add_front((linked_node *) new dirty_rect(p->dx1,y2+1,p->dx2,p->dy2));
  855.               else 
  856.                 dirties.add_front((linked_node *) new dirty_rect(p->dx1,p->dy1,p->dx2,y1-1));
  857.             } else if (y1>p->dy1 && y2<p->dy2)
  858.               dirties.add_front((linked_node *) new dirty_rect(p->dx1,y2+1,p->dx2,p->dy2));
  859.             dirties.unlink((linked_node *) p);
  860.             delete p;
  861.           }
  862.         }
  863.       }
  864.     }
  865.   }
  866. }
  867.  
  868. // specifies that an area is a dirty
  869. void image_descriptor::add_dirty(int x1, int y1, int x2, int y2)
  870. {
  871.   short i;
  872.   dirty_rect *p;
  873.   if (keep_dirt)
  874.   {
  875.     if (x1<0) x1=0;
  876.     if (y1<0) y1=0;
  877.     if (x2>=(int)l) x2=l-1;
  878.     if (y2>=(int)h) y2=h-1;
  879.     if (x1>x2) return;
  880.     if (y1>y2) return ;
  881.     i=dirties.number_nodes();
  882.     if (!i)
  883.       dirties.add_front((linked_node *) new dirty_rect(x1,y1,x2,y2));
  884.     else if (i>=MAX_DIRTY)
  885.     {
  886.       dirties.add_front((linked_node *) new dirty_rect(x1,y1,x2,y2));
  887.       reduce_dirties();  // reduce to one dirty rectangle, we have to many
  888.     }
  889.     else
  890.     {  
  891.       for (p=(dirty_rect *)dirties.first();i>0;i--)
  892.       {
  893.  
  894.         // check to see if this new rectangle completly encloses the check rectangle
  895.     if (x1<=p->dx1 && y1<=p->dy1 && x2>=p->dx2 && y2>=p->dy2)
  896.     {
  897.       dirty_rect *tmp=(dirty_rect*) p->next();
  898.       dirties.unlink((linked_node *)p);
  899.       delete p;
  900.       if (!dirties.first())
  901.           i=0;
  902.       else p=tmp;      
  903.     }    
  904.     else if (!(x2<p->dx1 || y2<p->dy1 || x1>p->dx2 || y1>p->dy2))
  905.     {      
  906.  
  907.  
  908.      
  909. /*          if (x1<=p->dx1) { a+=p->dx1-x1; ax1=x1; } else ax1=p->dx1;
  910.           if (y1<=p->dy1) { a+=p->dy1-y1; ay1=y1; } else ay1=p->dy1; 
  911.           if (x2>=p->dx2) { a+=x2-p->dx2; ax2=x2; } else ax2=p->dx2;
  912.           if (y2>=p->dy2) { a+=y2-p->dy2; ay2=y2; } else ay2=p->dy2;
  913.       
  914.       if (a<50) 
  915.       { p->dx1=ax1;                         // then expand the dirty
  916.         p->dy1=ay1;
  917.         p->dx2=ax2;
  918.         p->dy2=ay2;
  919.         return ;
  920.       } 
  921.       else */
  922.         {
  923.           if (x1<p->dx1)
  924.             add_dirty(x1,max(y1,p->dy1),p->dx1-1,min(y2,p->dy2));
  925.           if (x2>p->dx2)
  926.             add_dirty(p->dx2+1,max(y1,p->dy1),x2,min(y2,p->dy2));
  927.           if (y1<p->dy1)
  928.             add_dirty(x1,y1,x2,p->dy1-1);
  929.           if (y2>p->dy2)
  930.             add_dirty(x1,p->dy2+1,x2,y2);
  931.           return ;
  932.         }
  933.         p=(dirty_rect *)p->next();
  934.       } else p=(dirty_rect *)p->next();      
  935.     
  936.       } 
  937.       CHECK(x1<=x2 && y1<=y2);
  938.       dirties.add_end((linked_node *)new dirty_rect(x1,y1,x2,y2)); 
  939.     }
  940.   }
  941. }
  942.  
  943. void image::bar      (short x1, short y1, short x2, short y2, unsigned char color)
  944. {
  945.   short y;
  946.   if (x1>x2 || y1>y2) return ;
  947.   if (special)
  948.   { x1=special->bound_x1(x1);
  949.     y1=special->bound_y1(y1);
  950.     x2=special->bound_x2(x2);
  951.     y2=special->bound_y2(y2);
  952.   }
  953.   else
  954.   { if (x1<0) x1=0;
  955.     if (y1<0) y1=0;
  956.     if (x2>=width())  x2=width()-1;
  957.     if (y2>=height()) y2=height()-1;
  958.   }
  959.   if (x2<0 || y2<0 || x1>=width() || y1>=height() || x2<x1 || y2<y1)
  960.     return ;
  961.   for (y=y1;y<=y2;y++)
  962.     memset(scan_line(y)+x1,color,(x2-x1+1));
  963.   add_dirty(x1,y1,x2,y2);
  964. }
  965.  
  966. void image::xor_bar  (short x1, short y1, short x2, short y2, unsigned char color)
  967. {
  968.   short y,x;
  969.   if (x1>x2 || y1>y2) return ;
  970.   if (special)
  971.   { x1=special->bound_x1(x1);
  972.     y1=special->bound_y1(y1);
  973.     x2=special->bound_x2(x2);
  974.     y2=special->bound_y2(y2);
  975.   }
  976.   else
  977.   { if (x1<0) x1=0;
  978.     if (y1<0) y1=0;
  979.     if (x2>=width())  x2=width()-1;
  980.     if (y2>=height()) y2=height()-1;
  981.   }
  982.   if (x2<0 || y2<0 || x1>=width() || y1>=height() || x2<x1 || y2<y1)
  983.     return ;
  984.  
  985.   unsigned char *sl=scan_line(y1)+x1; 
  986.   for (y=y1;y<=y2;y++)
  987.   {
  988.     unsigned char *s=sl;
  989.     for (x=x1;x<=x2;x++,s++)
  990.       *s=(*s)^color;
  991.     sl+=w;
  992.   }
  993.  
  994.   add_dirty(x1,y1,x2,y2);
  995. }
  996.  
  997.  
  998. void image::unpack_scanline(short line, char bitsperpixel)
  999. {
  1000.   short x;
  1001.   unsigned char *sl,*ex,mask,bt,sh;
  1002.   ex=(unsigned char *)jmalloc(width(),"image::unpacked scanline");
  1003.   sl=scan_line(line);
  1004.   memcpy(ex,sl,width());
  1005.  
  1006.   if (bitsperpixel==1)      { mask=128;           bt=8; }
  1007.   else if (bitsperpixel==2) { mask=128+64;        bt=4; }
  1008.   else                 {  mask=128+64+32+16; bt=2; }
  1009.  
  1010.   for (x=0;x<width();x++)
  1011.   { sh=((x%bt)<<(bitsperpixel-1));
  1012.     sl[x]=(ex[x/bt]&(mask>>sh))>>(bt-sh-1);
  1013.   }
  1014.  
  1015.   jfree((char *)ex);
  1016. }
  1017.  
  1018. void image::dither(palette *pal)
  1019. {
  1020.   short x,y,i,j;
  1021.   unsigned char dt_matrix[]={0,  136,24, 170,
  1022.            68, 204,102,238,
  1023.            51, 187, 17,153,
  1024.            119,255, 85,221};
  1025.  
  1026.   unsigned char *sl;
  1027.   for (y=height()-1;y>=0;y--)
  1028.   {
  1029.     sl=scan_line(y);
  1030.     for (i=0,j=y%4,x=width()-1;x>=0;x--)
  1031.     {
  1032.       if (pal->red(sl[x])>dt_matrix[j*4+i])
  1033.     sl[x]=255;
  1034.       else sl[x]=0;
  1035.       if (i==3) i=0; else i++;
  1036.     }
  1037.   }
  1038. }
  1039.  
  1040. void image_descriptor::clear_dirties()
  1041. {
  1042.   dirty_rect *dr;
  1043.   dr=(dirty_rect *)dirties.first();  
  1044.   while (dr)
  1045.   { dirties.unlink(dr);
  1046.     delete dr;
  1047.     dr=(dirty_rect *)dirties.first();
  1048.   }
  1049. }
  1050.  
  1051. void image::resize(short new_width, short new_height)
  1052. {
  1053.   int old_width=width(),old_height=height();
  1054.   unsigned char *im=(unsigned char *)jmalloc(width()*height(),"image::resized");
  1055.   memcpy(im,scan_line(0),width()*height());
  1056.  
  1057.   delete_page();
  1058.   make_page(new_width,new_height,NULL);
  1059.   w=new_width;      // set the new hieght and width
  1060.   h=new_height;
  1061.  
  1062.   unsigned char *sl1,*sl2;
  1063.   short y,y2,x2;
  1064.   double yc,xc,yd,xd;
  1065.  
  1066.  
  1067.  
  1068.   yc=(double)old_height/(double)new_height;
  1069.   xc=(double)old_width/(double)new_width;
  1070.   for (y2=0,yd=0;y2<new_height;yd+=yc,y2++)
  1071.   {
  1072.     y=(int)yd;
  1073.     sl1=im+y*old_width;
  1074.     sl2=scan_line(y2);
  1075.     for (xd=0,x2=0;x2<new_width;xd+=xc,x2++)
  1076.     { sl2[x2]=sl1[(int)xd]; }
  1077.   }
  1078.   jfree(im);
  1079.   if (special) special->resize(new_width,new_height);
  1080. }
  1081.  
  1082. void image::scroll(short x1, short y1, short x2, short y2, short xd, short yd)
  1083. {
  1084.   short cx1,cy1,cx2,cy2;
  1085.   CHECK(x1>=0 && y1>=0 && x1<x2 && y1<y2 && x2<width() && y2<height());
  1086.   if (special)
  1087.   {
  1088.     special->get_clip(cx1,cy1,cx2,cy2);
  1089.     x1=max(x1,cx1); y1=max(cy1,y1); x2=min(x2,cx2); y2=min(y2,cy2);
  1090.   }
  1091.   short xsrc,ysrc,xdst,ydst,xtot=x2-x1-abs(xd)+1,ytot,xt;
  1092.   unsigned char *src,*dst;
  1093.   if (xd<0) { xsrc=x1-xd; xdst=x1; } else { xsrc=x2-xd; xdst=x2; }
  1094.   if (yd<0) { ysrc=y1-yd; ydst=y1; } else { ysrc=y2-yd; ydst=y2; }
  1095.   for (ytot=y2-y1-abs(yd)+1;ytot;ytot--)
  1096.   { src=scan_line(ysrc)+xsrc;
  1097.     dst=scan_line(ydst)+xdst;
  1098.     if (xd<0)
  1099.       for (xt=xtot;xt;xt--)
  1100.         *(dst++)=*(src++);
  1101.       else for (xt=xtot;xt;xt--)
  1102.         *(dst--)=*(src--);
  1103.     if (yd<0) { ysrc++; ydst++; } else { ysrc--; ydst--; }
  1104.   }
  1105.   add_dirty(x1,y1,x2,y2);
  1106. }
  1107.  
  1108.  
  1109. image *image::create_smooth(short smoothness)
  1110. {
  1111.   short i,j,k,l,t,d;
  1112.   image *im;
  1113.   CHECK(smoothness>=0);
  1114.   if (!smoothness) return NULL;
  1115.   d=smoothness*2+1;
  1116.   d=d*d;
  1117.   im=new image(width(),height());
  1118.   for (i=0;i<width();i++)
  1119.     for (j=0;j<height();j++)
  1120.     {
  1121.       for (t=0,k=-smoothness;k<=smoothness;k++)
  1122.     for (l=-smoothness;l<=smoothness;l++)
  1123.       if (i+k>smoothness && i+k<width()-smoothness && j+l<height()-smoothness && j+l>smoothness)
  1124.         t+=pixel(i+k,j+l);
  1125.       else t+=pixel(i,j);
  1126.       im->putpixel(i,j,t/d);
  1127.     }
  1128.   return im;
  1129. }
  1130.  
  1131. void image::wiget_bar(short x1, short y1, short x2, short y2, 
  1132.        unsigned char light, unsigned char med, unsigned char dark)
  1133. {
  1134.   line(x1,y1,x2,y1,light);
  1135.   line(x1,y1,x1,y2,light);
  1136.   line(x2,y1+1,x2,y2,dark);
  1137.   line(x1+1,y2,x2-1,y2,dark);
  1138.   bar(x1+1,y1+1,x2-1,y2-1,med);
  1139. }
  1140.  
  1141. class fill_rec
  1142. {
  1143. public :
  1144.   short x,y;
  1145.   fill_rec *last;
  1146.   fill_rec(short X, short Y, fill_rec *Last)
  1147.   { x=X; y=Y; last=Last; }
  1148. } ;
  1149.  
  1150. void image::flood_fill(short x, short y, unsigned char color)
  1151. {
  1152.   unsigned char *sl,*above,*below;
  1153.   fill_rec *recs=NULL,*r;
  1154.   unsigned char fcolor;
  1155.   sl=scan_line(y);
  1156.   fcolor=sl[x];
  1157.   if (fcolor==color) return ;
  1158.   do
  1159.   {
  1160.     if (recs)
  1161.     { r=recs;
  1162.       recs=recs->last;
  1163.       x=r->x; y=r->y;
  1164.       delete r;
  1165.     }
  1166.     sl=scan_line(y);
  1167.     if (sl[x]==fcolor)
  1168.     {
  1169.       while (sl[x]==fcolor && x>0) x--;
  1170.       if (sl[x]!=fcolor) x++;
  1171.       if (y>0)
  1172.       {
  1173.         above=scan_line(y-1);
  1174.         if (above[x]==fcolor)
  1175.         { r=new fill_rec(x,y-1,recs);
  1176.           recs=r;  
  1177.         }
  1178.       }
  1179.       if (y<height()-1)
  1180.       {
  1181.         above=scan_line(y+1);
  1182.         if (above[x]==fcolor)
  1183.         { r=new fill_rec(x,y+1,recs);
  1184.           recs=r;
  1185.         }
  1186.       }
  1187.  
  1188.  
  1189.  
  1190.       do
  1191.       {
  1192.         sl[x]=color; 
  1193.         if (y>0)
  1194.         { above=scan_line(y-1);
  1195.           if (x>0 && above[x-1]!=fcolor && above[x]==fcolor)
  1196.           { r=new fill_rec(x,y-1,recs);
  1197.             recs=r;  
  1198.           }
  1199.         }
  1200.         if (y<height()-1)
  1201.         { below=scan_line(y+1);
  1202.           if (x>0 && below[x-1]!=fcolor && below[x]==fcolor)
  1203.           { r=new fill_rec(x,y+1,recs);
  1204.             recs=r;  
  1205.           }
  1206.         }
  1207.         x++;
  1208.       } while (sl[x]==fcolor && x<width());
  1209.       x--;
  1210.       if (y>0)
  1211.       {
  1212.         above=scan_line(y-1);
  1213.         if (above[x]==fcolor)
  1214.         { r=new fill_rec(x,y-1,recs);
  1215.           recs=r;
  1216.         }
  1217.       }
  1218.       if (y<height()-1)
  1219.       {
  1220.         above=scan_line(y+1);
  1221.         if (above[x]==fcolor)
  1222.         { r=new fill_rec(x,y+1,recs);
  1223.           recs=r;
  1224.         }
  1225.       }
  1226.     }
  1227.   } while (recs);
  1228. }
  1229.  
  1230.  
  1231. #define LED_L 5
  1232. #define LED_H 5
  1233. void image::burn_led(short x, short y, long num, short color, short scale)
  1234. {
  1235.   char st[100];
  1236.   short ledx[]={1,2,1,2,3,3,3,3,1,2,0,0,0,0};
  1237.   short ledy[]={3,3,0,0,1,2,4,6,7,7,4,6,1,2};
  1238.  
  1239.   short dig[]={2+4+8+16+32+64,4+8,2+4+1+32+16,2+4+1+8+16,64+1+4+8,
  1240.              2+64+1+8+16,64+32+1+8+16,2+4+8,1+2+4+8+16+32+64,64+2+4+1+8,1};
  1241.   short xx,yy,zz;
  1242.   sprintf(st,"%8ld",num);
  1243.   for (xx=0;xx<8;xx++)
  1244.   {
  1245.     if (st[xx]!=' ')
  1246.     {
  1247.       if (st[xx]=='-')
  1248.     zz=10;
  1249.       else
  1250.     zz=st[xx]-'0';
  1251.       for (yy=0;yy<7;yy++)
  1252.     if ((1<<yy)&dig[zz])
  1253.       line(x+ledx[yy*2]*scale,y+ledy[yy*2]*scale,x+ledx[yy*2+1]*scale,
  1254.         y+ledy[yy*2+1]*scale,color);
  1255.     }
  1256.     x+=6*scale;
  1257.   }
  1258. }
  1259.  
  1260. unsigned char dither_matrix[]={0,  136,24, 170,
  1261.              68, 204,102,238,
  1262.              51, 187, 17,153,
  1263.              119,255, 85,221};
  1264.  
  1265. image *image::copy_part_dithered (short x1, short y1, short x2, short y2)
  1266. {
  1267.   short x,y,cx1,cy1,cx2,cy2,ry,rx,bo,dity,ditx;
  1268.   image *ret;
  1269.   unsigned char *sl1,*sl2;
  1270.   get_clip(cx1,cy1,cx2,cy2);
  1271.   if (y1<cy1) y1=cy1;
  1272.   if (x1<cx1) x1=cx1;
  1273.   if (y2>cy2) y2=cy2;
  1274.   if (x2>cx2) x2=cx2;
  1275.   CHECK(x2>=x1 && y2>=y1);
  1276.   if (x2<x1 || y2<y1) return NULL;
  1277.   ret=new image((x2-x1+8)/8,(y2-y1+1));
  1278.   if (!last_loaded())
  1279.     ret->clear();
  1280.   else 
  1281.     for (y=y1,ry=0,dity=(y1%4)*4;y<=y2;y++,ry++)
  1282.     {
  1283.       sl1=ret->scan_line(ry);     // sl1 is the scan linefo the return image
  1284.       sl2=scan_line(y);          // sl2 is the orginal image scan line
  1285.       memset(sl1,0,(x2-x1+8)/8);
  1286.       for (bo=7,rx=0,x=x1,ditx=x1%4;x<=x2;x++)
  1287.       {
  1288.         if (last_loaded()->red(sl2[x])>dither_matrix[ditx+dity]) 
  1289.           sl1[rx]|=1<<bo;
  1290.         if (bo!=0)
  1291.       bo--;
  1292.         else
  1293.         {
  1294.         rx++;
  1295.       bo=7;
  1296.         }
  1297.         ditx+=1; if (ditx>3) ditx=0;
  1298.       }
  1299.       dity+=4; if (dity>12) dity=0;
  1300.     }
  1301.   return ret;
  1302. }
  1303.  
  1304. void image::flip_x()
  1305. {
  1306.   unsigned char *rev=(unsigned char *)jmalloc(width(),"image tmp::flipped_x"),*sl;
  1307.   CONDITION(rev,"memory allocation"); 
  1308.   int y,x,i;
  1309.   for (y=0;y<height();y++)
  1310.   { sl=scan_line(y);
  1311.     for (i=0,x=width()-1;x>=0;x--,i++)
  1312.       rev[i]=sl[x]; 
  1313.     memcpy(sl,rev,width());
  1314.   }
  1315.   jfree(rev);
  1316. }
  1317.  
  1318. void image::flip_y()
  1319. {
  1320.   unsigned char *rev=(unsigned char *)jmalloc(width(),"image::flipped_y"),*sl;
  1321.   CONDITION(rev,"memory allocation"); 
  1322.   int y;
  1323.   for (y=0;y<height()/2;y++)
  1324.   { sl=scan_line(y);
  1325.     memcpy(rev,sl,width());
  1326.     memcpy(sl,scan_line(height()-y-1),width());
  1327.     memcpy(scan_line(height()-y-1),rev,width());
  1328.   }
  1329. }
  1330.  
  1331. void image::make_color(unsigned char color)
  1332. {
  1333.   unsigned char *sl;
  1334.   int y,x;
  1335.   for (y=0;y<height();y++)
  1336.   {
  1337.     sl=scan_line(y);
  1338.     for (x=width();x;x--,sl++)
  1339.       if (*sl) 
  1340.         *sl=color;
  1341.   }
  1342. }
  1343.